/** @file bt_isr.c
  *  
  * @brief This file contains the interrupt handling functions
  * of Bluetooth driver.
  * 
  * (c) Copyright 2003-2007, Marvell International Ltd.
  * All Rights Reserved
  */

#include <windows.h>

#include "bt_dev.h"
#include "bt_func.h"
#include "If.h"
#include "igxBug.h"


SD_API_STATUS SDInterruptCallback(SD_DEVICE_HANDLE hDevice, 
                                  PVOID pContext)
{                         
    PMRVDRV_ADAPTER  pAdapter;
    UCHAR            ucHostIntStatus;
    UCHAR            ucCardStatus;
    SD_API_STATUS    status;


    pAdapter = (PMRVDRV_ADAPTER)pContext;

    DBGPRINT(DBG_ISR, (L"++BT SDInterruptCallback++\n\r"));
        
    // read Host Int Status register (function 1, addr 6)
    status = If_ReadRegister(pAdapter,
                             //SD_IO_READ ,
                             BT_FUNC,
                             HCR_HOST_INT_STATUS_REGISTER, 
                             FALSE,
                             &ucHostIntStatus,
                             sizeof(ucHostIntStatus));
    if (!SD_API_SUCCESS(status))
    {
        DBGPRINT(DBG_ISR, (L"Unable to read Host interrupt status register\n\r"));
        DBGPRINT(DBG_ISR, (L"ISR read error 1\n\r") );
        return status;
    } 

    EnterCriticalSection(&pAdapter->IntCriticalSection);   
    pAdapter->gHostIntStatus |= ucHostIntStatus; 
    LeaveCriticalSection(&pAdapter->IntCriticalSection);   
    ucCardStatus = ~ucHostIntStatus;    

    ucCardStatus &= 0x1f;
    status = If_WriteRegister(pAdapter,
                              //SD_IO_WRITE,          
                              BT_FUNC,     
                              HCR_HOST_INT_STATUS_REGISTER,
                              FALSE,
                              &ucCardStatus,
                              sizeof(ucCardStatus));   
    if (!SD_API_SUCCESS(status))
    {
        DBGPRINT(DBG_ISR, (L"Unable to clear Host interrupt status register\n\r"));
        DBGPRINT(DBG_ISR, (L"ISR read error 2\n\r") );
        return status;
    } 

    if (ucHostIntStatus == 0xff)
    {
        // card removed?
        DBGPRINT(DBG_ISR, (L"read 0xff\n\r"));
        return SD_API_STATUS_SUCCESS;
    }  

    SetEvent(pAdapter->hControllerInterruptEvent);

    pAdapter->ps_state = PS_AWAKE;
    pAdapter->hs_state = HS_DEACTIVATED;

    return SD_API_STATUS_SUCCESS;
}


#ifdef IF_SDIO
///////////////////////////////////////////////////////////////////////////////
//  SDSlotEventCallBack - slot event callback for fast-path events
//  Input:  hDevice - device handle
//          pContext - device specific context that was registered
//          SlotEventType - slot event type
//          pData - Slot event data (can be NULL)
//          DataLength - length of slot event data (can be 0)
//  Output:
//  Returns: 
//  Notes:  
//
//      If this callback is registered the client driver can be notified of
//      slot events (such as device removal) using a fast path mechanism.  This
//      is useful if a driver must be notified of device removal 
//      before its XXX_Deinit is called.  
//
//      This callback can be called at a high thread priority and should only
//      set flags or set events.  This callback must not perform any
//      bus requests or call any apis that can perform bus requests.
///////////////////////////////////////////////////////////////////////////////
VOID SDSlotEventCallBack(SD_DEVICE_HANDLE    hDevice,
                         PVOID               pContext,
                         SD_SLOT_EVENT_TYPE  SlotEventType,
                         PVOID               pData,
                         DWORD               DataLength)
{
    PMRVDRV_ADAPTER pAdapter;

    DBGPRINT(DBG_HELP, (L"++SDSlotEventCallBack++: event 0x%x\n\r", 
                        SlotEventType));

    switch (SlotEventType)
    {
        case SDCardEjected :
            DBGPRINT(DBG_ERROR, (L"SDCard Ejected Event !\n\r"));
            pAdapter = (PMRVDRV_ADAPTER)pContext;

            SDIODisconnectInterrupt(pAdapter->hDevice);

            pAdapter->CardRemoved = TRUE;
            SetEvent(pAdapter->hReadPacketEvent);

            if (Adapter->bWaitForCmd == TRUE)
            {
                SetEvent(Adapter->hCmdRespEvent);
                Sleep(100);
            }
#ifdef INIT_THREAD
            SetEvent(Adapter->hDelayTimerEvent);
            Sleep(100);
#endif
            break;
        default :
            break;
    }
}
#endif //IF_SDIO


VOID MrvIstThreadProc(PVOID pContext)
{
    PMRVDRV_ADAPTER pAdapter = (PMRVDRV_ADAPTER) pContext;
    DWORD waitStatus;
    UCHAR ucLHostIntStatus = 0; 


    DBGPRINT(DBG_TX|DBG_HELP, (L"[MrvIstThreadProc] pAdapter->SdioIstThreadPriority = %d\n\r",
                              pAdapter->SdioIstThreadPriority));
   
    CeSetThreadPriority(GetCurrentThread(), pAdapter->SdioIstThreadPriority); 
    {
        DBGPRINT(DBG_RX|DBG_TX|DBG_HELP, (L"IstThread priority: %d\n\r",
                                         CeGetThreadPriority(GetCurrentThread())));
    }
    SetEvent(pAdapter->hThreadReadyEvent);

    while (1)
    {
        if (Adapter->CardRemoved == TRUE)
        {
            DBGPRINT(DBG_ERROR, (L"IST Thread terminate due to card removed !\n\r"));
            return;
        }

        waitStatus = WaitForSingleObject(pAdapter->hControllerInterruptEvent,
                                         INFINITE);
        if (WAIT_OBJECT_0 != waitStatus)
        {
            return;
        }

        EnterCriticalSection(&pAdapter->IntCriticalSection);
        ucLHostIntStatus = pAdapter->gHostIntStatus;
        pAdapter->gHostIntStatus &= ~ucLHostIntStatus;
        LeaveCriticalSection(&pAdapter->IntCriticalSection);

        if (ucLHostIntStatus & UPLOAD_HOST_INT_STATUS_RDY)    /* 0x1 */
        {
            /* Rx_Ready INT */
            DBGPRINT(DBG_ISR, (L"++UPLOAD_RDY++\n\r"));
            HandleRxReadyEvent(pAdapter);
        }
 
        if (ucLHostIntStatus & DOWNLOAD_HOST_INT_STATUS_RDY)  /* 0x2 */
        {
            /* Tx_Done INT */
            DBGPRINT(DBG_ISR, (L"++DOWNLOAD_RDY++\n\r"));
            // Check Tx Q for more packet sending.
        }

    } // end of while loop  
}



VOID MrvIstBtProc(PVOID pContext, UCHAR IntStatus )
{
    PMRVDRV_ADAPTER pAdapter = (PMRVDRV_ADAPTER) pContext;
    SD_API_STATUS    status;
    UCHAR ucLHostIntStatus;

    ucLHostIntStatus = IntStatus;

    do
    {
        if (Adapter->CardRemoved == TRUE)
        {
            DBGPRINT(DBG_ERROR, (L"IST Thread terminate due to card removed !\n\r"));
            return;
        }

        if (ucLHostIntStatus & UPLOAD_HOST_INT_STATUS_RDY)    /* 0x1 */
        {
            /* Rx_Ready INT */
            DBGPRINT(DBG_ISR, (L"++UPLOAD_RDY++\n\r"));
            HandleRxReadyEvent(pAdapter);
        }
 
        if (ucLHostIntStatus & DOWNLOAD_HOST_INT_STATUS_RDY)  /* 0x2 */
        {
            /* Tx_Done INT */
            DBGPRINT(DBG_ISR, (L"++DOWNLOAD_RDY++\n\r"));
            // Check Tx Q for more packet sending.
        }

        ucLHostIntStatus = 0;

        status = If_ReadRegister(pAdapter,
                                 BT_FUNC,
                                 HCR_HOST_INT_STATUS_REGISTER, 
                                 FALSE,
                                 &ucLHostIntStatus,
                                 sizeof(ucLHostIntStatus));
        if (!SD_API_SUCCESS(status))
        {
            DBGPRINT(DBG_ISR, (L"BT - Unable to read Host interrupt status register\n\r"));
            break;
        } 

    } while ( ucLHostIntStatus );
    
}
